package vip.xiaonuo.core.filter;

import cn.dev33.satoken.router.SaRouter;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import org.springframework.util.StreamUtils;
import org.springframework.web.util.HtmlUtils;
import vip.xiaonuo.core.util.MySaSignUtil;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

import static cn.dev33.satoken.SaManager.log;


public class RequestReaderHttpServletRequestWrapper  extends HttpServletRequestWrapper {
    HttpServletRequest orgRequest = null;
    byte[] requestBody = null;//用于将流保存下来
    private Map<String, String[]> parameterMap; // 所有参数的Map集合

    /**
     * 不需要验证sign的接口
     */
    private static final String[] NO_SIGN_PATH_ARR = {
            /* 主入口 */
            "/",

            /* 静态资源 */
            "/favicon.ico",
            "/druid/**",
            "/images/**",
            "/swagger-ui/**",
            "/v3/**",

    };
    /**
     * other 参数所包含的参数信息
     */
    private Map<String, String[]> otherMap;

        public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException{
            super(request);
            orgRequest = request;
            parameterMap = request.getParameterMap();
            otherMap = new ConcurrentHashMap<>();
            requestBody = StreamUtils.copyToByteArray(request.getInputStream());
            if(!SaRouter.isMatchCurrURI(NO_SIGN_PATH_ARR)){
                //效验请求中的token
                MySaSignUtil.checkRequest(request,new String(requestBody));
            }
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {

            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

            return new ServletInputStream() {

                @Override
                public int read() throws IOException {
                    return bais.read();
                }

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {

                }
            };
        }

        @Override
        public BufferedReader getReader() throws IOException{
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

    // 重写几个HttpServletRequestWrapper中的方法
    /**
     * 获取所有参数名
     *
     * @return 返回所有参数名
     */
    @Override
    public Enumeration<String> getParameterNames() {
        Vector<String> vector = new Vector<String>(parameterMap.keySet());
        vector.addAll(otherMap.keySet());
        return vector.elements();
    }
    /**
     * 覆盖getParameter方法，将参数名和参数值都做xss过滤。<br/>
     * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取<br/>
     * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
     */
    @Override
    public String getParameter(String name) {
//		System.out.println("NewXssFilter处理前的 name="+name+"--Value = " + Arrays.toString(super.getParameterValues(name)));

        String value = orgRequest.getParameter(xssEncode(name));
        if (value != null) {
            value = xssEncode(value,name);
        }

//		System.out.println("NewXssFilter处理后的 Value = " + value);

        return value;
    }

    /**
     * 获取指定参数名的所有值的数组
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] values = parameterMap.get(name);
        try{
            if (values == null) {
                if(null != otherMap){
                    values = otherMap.get(name);
                }
            }
            if(values != null) {
                for(int i=0;i<values.length;i++) {
                    values[i]=xssEncode(values[i],name);
                }
            }
        }catch (Throwable e){
            log.error("getParameterValues.is.system.error",e);
        }
        return values != null ? values : super.getParameterValues(name);
    }
    /**
     * 覆盖getHeader方法，将参数名和参数值都做xss过滤。<br/>
     * 如果需要获得原始的值，则通过super.getHeaders(name)来获取<br/>
     * getHeaderNames 也可能需要覆盖
     */
    @Override
    public String getHeader(String name) {

        String value = orgRequest.getHeader(xssEncode(name));
        if (value != null) {
            value = xssEncode(value);
        }
        return value;
    }

    /**
     * 将容易引起xss漏洞的半角字符直接替换成全角字符
     *
     * @param s
     * @return
     */
    private String xssEncode(String s) {
        if (s == null || s.isEmpty()) {
            return s;
        }
        return filter(s);
    }
    private String xssEncode(String s, String name) {
        if (s == null || s.isEmpty() ||name==null) {
            return s;
        }
        String cleanOutput = "";
        try {
            //追加替换
            if(name.equals("detail")
                    || name.equals("content")
                    || name.equals("certImgs")
                    || name.equals("TptrolJon")
                    || name.equals("userDatas")
                    || name.equals("compFax")
                    || name.indexOf("json")!=-1
                    || name.indexOf("Json")!=-1
            ) {
                cleanOutput=HtmlUtils.htmlEscape(s,"UTF-8");
                //json参数双引号还原
                cleanOutput=cleanOutput.replaceAll("&quot;", "\"");
            }else {
                //非json参数过滤引号
                cleanOutput=HtmlUtils.htmlEscape(s,"UTF-8");

            }

        } catch (Exception e) {
            log.error("xss处理失败={}",e);
        }

        return cleanOutput;
    }
    /**
     * 删除危险字符
     * @param dirtyInput
     * @return
     */
    private String filter(String dirtyInput) {
        String cleanOutput = "";
        try {
            cleanOutput= HtmlUtils.htmlEscape(dirtyInput,"UTF-8");
            //追加替换
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cleanOutput;
    }

    /**
     * 获取最原始的request
     *
     * @return
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }

    /**
     * 获取最原始的request的静态方法
     *
     * @return
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
        if (req instanceof RequestReaderHttpServletRequestWrapper) {
            return ((RequestReaderHttpServletRequestWrapper) req).getOrgRequest();
        }

        return req;
    }
}
